home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Arsenal Files 8
/
The Arsenal Files Collection #8 (Arsenal Computer) (1996).ISO
/
prg_basi
/
qbsvga.zip
/
QBSVGA.BAS
< prev
next >
Wrap
BASIC Source File
|
1996-08-29
|
68KB
|
2,515 lines
DEFSNG A-Z
'
' Subroutine BSCREEN emulates the function of QB's SCREEN statement.
' It uses subroutine FINDVESA to find a video mode supported by a VESA
' bios that corresponds to a "QB-type" mode specified by MODE. The
' resolutions for each supported MODE integer are given below.
'
' MODE = 14: 640 x 480 x 256
' MODE = 15: 800 x 600 x 16
' MODE = 16: 800 x 600 x 256
' MODE = 17: 1024 x 768 x 16
' MODE = 18: 1024 x 768 x 256
' MODE = 19: 1200 x 1024 x 16
' MODE = 20: 1200 x 1024 x 256
' MODE = 21: 1600 x 1200 x 16
' MODE = 22: 1600 x 1200 x 256
' MODE = 23: 132 x 25 x 16 (text)
' MODE = 24: 132 x 43 x 16 (text)
' MODE = 25: 132 x 50 x 16 (text)
'
' These routines should not be used with modes not specified here. Mode
' 0 is an allowable input; it corresponds to QB's SCREEN 0 and gets
' translated here to bios mode 3. (Except for more colors, I'm not aware
' of any higher modes, anyway, and why would you want to use these
' routines with the lower modes? QB's SCREEN statement will do that.) If
' a mode with the desired resolution and colors cannot be found, a mode
' will still be selected if one can be found with the desired resolution
' and *more* colors than necessary.
'
' The first four inputs are just as would be used with QB's SCREEN
' statement except that CL is the default color to print with, not some
' switch that determines whether color is displayed at all. Unlike the
' SCREEN statement, all parameters much be specified in the CALL. If the
' input video mode is the one that is already in effect, BSCREEN can be
' used to simply change default colors or displayed/active pages. (You
' might want to use subroutine BCOLOR for the former purpose.) BSCREEN
' should be called before any of the other routines are called.
'
SUB BSCREEN(MODE,CL,APAGE,VPAGE)
DIM CMODE AS INTEGER
'
' Store active page and default color in global variables. (Alias VPAGE
' with VP and make sure its value is valid.)
'
ACPAGE=APAGE : IF ACPAGE<0 THEN ACPAGE=0
DEFLTC=CL : IF DEFLTC<=0 THEN DEFLTC=7
VP=VPAGE : IF VP<0 THEN VP=0
'
' Get current video mode. If it is same as one being set, no mode change
' is made. The routine is just being used to change default colors
' (subroutine BCOLOR is simpler to use for that purpose) or pages. (The
' value of CMODE may get changed after VESA-awareness is determined.)
'
INREGS.AX=&HF00
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
CMODE=OUTREGS.AX AND &HFF
'
' Set visible page.
'
INREGS.AX=CINT(VP)+1280
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
'
' Make correlation between "QB-type" modes and resolution of bios mode to
' be searched for. (Set default mode data in case invalid mode was input.)
'
HR=800 : VR=600 : NC=16
IF MODE=14 THEN HR=640 : VR=480
IF MODE=15 OR MODE=16 THEN HR=800 : VR= 600
IF MODE=17 OR MODE=18 THEN HR=1024 : VR=768
IF MODE=19 OR MODE=20 THEN HR=1280 : VR=1024
IF MODE=21 OR MODE=22 THEN HR=1600 : VR=1200
IF MODE=23 THEN VR=25
IF MODE=24 THEN VR=43
IF MODE=25 THEN VR=50
IF MODE=0 OR MODE=15 OR MODE=17 OR MODE=19 OR MODE=21 OR MODE>22 THEN NC=16
IF MODE=14 OR MODE=16 OR MODE=18 OR MODE=20 OR MODE=22 THEN NC=256
IF MODE=23 OR MODE=24 OR MODE=25 THEN HR=132
'
' Define global resolution limits (zero-based) and viewport defaults.
'
HMAX=HR-1 : VMAX=VR-1 : VXL=0 : VYL=0 : VXR=HMAX : VYR=VMAX
'
' Set VCOL to a negative number so other routines can tell that BVIEW
' wasn't called yet.
'
VCOL=-1
IF MODE<>0 THEN
'
' SCREEN is not being reset to text mode. Find VESA mode with desired
' resolution. If FINDVESA can't find a requisite VESA mode, whether
' because system isn't VESA-aware or other reasons, BMODE is returned as
' -1. (If system is detected as VESA aware, an "error code" of 0 is
' defined via VESSUP variable. If VESA cannot be detected, VESSUP is set
' to unity.) Before using FINDVESA, however, look for overriding bios
' mode definition via DOS environment variable. (This environment
' is SET with the syntax "MODE##=bios-mode", where ## is the two-digit
' QB-type mode integer that corresponds to bios-mode.)
'
QBMODE$="MODE"+LTRIM$(RTRIM$(STR$(MODE)))
EMODE$=MID$(LTRIM$(ENVIRON$(QBMODE$)),1,80)
BMODE=VAL("&H0"+EMODE$)
'
' In case FINDVESA isn't going to be used to find a VESA video mode or
' it *is* going to be used and in case it fails, set default bit planes
' per pixel and bits per pixel parameters.
'
BITPLANES=1 : BITSPIXEL=8
IF BMODE=0 THEN
'
' "MODE##" environment variable didn't exist for input QB-type mode.
'
CALL FINDVESA(BMODE,HR,VR,NC)
'
' Except for text mode 3, there are no bios modes less than 4 that are
' of concern here. (There aren't likely any below 13h of any importance.
' I'm just taking into account "wierd" video adapters, such as mine, which
' will do a hex mode B.)
'
IF BMODE>=4 THEN
'
' VESA mode was found, hence, system is VESA-aware. Redetermine current
' video mode.
'
INREGS.AX=&H4F03
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
CMODE=OUTREGS.BX
IF CMODE<>BMODE THEN
'
' VESA mode was found and it is different from current mode; change video
' mode.
'
INREGS.AX=&H4F02
INREGS.BX=BMODE
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
IF MODE<23 THEN
'
' Initialize mouse if driver is installed via interrupt 33h.
'
IF QRYMOUSE=-1 THEN CALL MOUSINIT
END IF
END IF
ELSE
'
' VESA mode couldn't be found. Assume "OEM SVGA" and ask user for
' hexadecimal mode integer that corresponds to desired video mode. Set
' VESSUP according to value of input bios mode. (Put screen in standard
' QB text mode so prompt can be seen in case it was already in some
' QB-unreadable graphics screen.)
'
INREGS.AX=3
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
SCREEN 0
RES$=LTRIM$(RTRIM$(STR$(HR)))+" x "+LTRIM$(RTRIM$(STR$(VR)))+" x "
RES$=RES$+LTRIM$(RTRIM$(STR$(NC)))
PRINT
PRINT " Couldn't find VESA mode giving resolution ";RES$;". What"
PRINT "hexadecimal bios mode integer gives you this resolution? (Press ENTER"
PRINT "to stop.)"
LINE INPUT M$
M$=RTRIM$(LTRIM$(M$))
IF M$="" THEN STOP
'
' Video mode is changed regardless of its present state when mode had to
' be prompted for. (Even if the above text-mode change hadn't occurred,
' the prompt for the mode needs to be cleared.)
'
VESSUP=1
INREGS.AX=VAL("&H"+M$)
'
' Use VESA call to set video mode if it is 100h or above. Otherwise,
' use standard bios call.
'
IF INREGS.AX>255 THEN
VESSUP=0
INREGS.BX=INREGS.AX
INREGS.AX=&H4F02
END IF
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
IF MODE<23 THEN
'
' Initialize mouse if driver is installed via interrupt 33h.
'
IF QRYMOUSE=-1 THEN CALL MOUSINIT
END IF
END IF
ELSE
'
' "MODE##" environment variable exists for desired mode. Set VESSUP
' according to value of bios mode.
'
VESSUP=1 : IF BMODE>255 THEN VESSUP=0
'
' Re-acquire and test current video mode before changing it.
'
IF VESSUP=1 THEN
INREGS.AX=&HF00
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
CMODE=OUTREGS.AX AND &HFF
INREGS.AX=BMODE
ELSE
INREGS.AX=&H4F03
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
CMODE=OUTREGS.BX
INREGS.AX=&H4F02
INREGS.BX=BMODE
END IF
IF CMODE<>BMODE THEN
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
IF MODE<23 THEN
'
' Initialize mouse if driver is installed via interrupt 33h.
'
IF QRYMOUSE=-1 THEN CALL MOUSINIT
END IF
END IF
END IF
'
' Global variable BVCBL is normally 0. BVIEW sets it to 1 just before
' calling BLINE to draw a border around the viewport. (BLINE uses this
' variable to know not to enforce viewport constraints when BVIEW tries to
' draw a box just outside of the viewport. (BVIEW resets it to unity when
' it's finished.) Define fictitious values for global mouse position
' variables.
'
BVCBL=0
ELSE
'
' SCREEN 0 is being emulated. Use what should be a standard text mode
' for any SVGA system. (This mode is also set regardless of whether or
' not the video state is already there.)
'
INREGS.AX=3
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
'
' Just to be safe, make sure QB knows what screen mode it's in. (The
' above call to interrupt 10 could probably be skipped, but QB's SCREEN 0
' by itself doesn't necessarily leave you in the text mode you want when
' the screen isn't initially in a mode that QB recognizes.)
'
SCREEN 0
END IF
END SUB
'
' This subroutine returns the VESA bios MODE integer (decimal) that has
' resolution HR x VR x NC, as input via the parameter list. If no such
' mode can be found, MODE is returned as -1. (If it finds a mode with
' the desired horizontal HR and vertical VR resolution but with more than
' NC colors, the mode is considered valid and is returned in MODE. (It
' will first try to find a mode with NC colors.))
'
' To qualify as a valid, the mode must be supported by both hardware and
' bios. (FINDVESA is usually called by BSCREEN. There is not much reason
' to call it directly.)
'
SUB FINDVESA(MODE,HR,VR,NC)
DIM VESA(1 TO 64) AS LONG,BYTE AS LONG,MD(1 TO 257) AS INTEGER,COLORS(1 TO 256)
DIM PLANES(1 TO 256)
SM=VARSEG(VESA(1)) : OS=VARPTR(VESA(1))
'
' Set VESSUP to unity in case VESA bios cannot be detected.
'
VESSUP=1
'
' Confirm VESA support and get pointer to list of supported VESA modes.
'
INREGS.AX=&H4F00
INREGS.ES=CINT(SM)
INREGS.DI=CINT(OS)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
DEF SEG=SM
T$=CHR$(PEEK(OS))+CHR$(PEEK(OS+1))+CHR$(PEEK(OS+2))+CHR$(PEEK(OS+3))
IF T$<>"VESA" THEN GOTO NOSUP
'
' VESA = VESA bios version number.
'
VESAFRC=PEEK(OS+4)
FIXFRC:
VESAFRC=VESAFRC/10
IF VESAFRC>=1 THEN GOTO FIXFRC
VESA=PEEK(OS+5)+VESAFRC
PSM=PEEK(OS+16)+256*PEEK(OS+17) : POF=PEEK(OS+14)+256*PEEK(OS+15)
'
' Look for video mode that supports desired resolution.
'
' NMODES counts number of modes (possibly with different colors) with
' desired resolution.
'
NMODES=1
NEWMODE:
DEF SEG=PSM
MD(NMODES)=PEEK(POF)+256*PEEK(POF+1) : POF=POF+2
IF MD(NMODES)=-1 THEN GOTO NOSUP
INREGS.AX=&H4F01
INREGS.CX=MD(NMODES)
INREGS.ES=CINT(SM)
INREGS.DI=CINT(OS)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
DEF SEG=SM
'
' First byte at segment SM stores "support information" about mode under
' analysis.
'
BYTE=CLNG(PEEK(OS)+256*PEEK(OS+1))
B$=LTRIM$(RTRIM$(BIN$(BYTE)))
'
' Bits 0 and 2 indicate support (or lack of it) in hardware and BIOS.
'
HARD$=MID$(B$,16,1)
BIOS$=MID$(B$,14,1)
IF HARD$="0" OR BIOS$="0" THEN GOTO NEWMODE
'
' Bit 4 indicates graphics or text mode.
'
GMSW$=MID$(B$,12,1)
'
' Bit 1 indicates the presence of extended information. If no extended
' information is available for this mode, it cannot be determined that
' it supports the required HR x VR resolution.
'
EXTINF$=MID$(B$,15,1)
IF EXTINF$="0" THEN GOTO NEWMODE
'
' Character sizes are needed to correct stored resolution data for some
' VESA bioses.
'
HS=PEEK(OS+22) : VS=PEEK(OS+23)
HRM=PEEK(OS+18)+256*PEEK(OS+19) : VRM=PEEK(OS+20)+256*PEEK(OS+21)
IF VESA<1.2 THEN
IF GMSW$="0" THEN HRM=HRM/HS : VRM=VRM/VS
IF (MD(NMODES)>=0 AND MD(NMODES)<=6) OR MD(NMODES)=13 THEN VRM=VRM/2
IF MD(NMODES)=14 OR MD(NMODES)=19 THEN VRM=VRM/2
END IF
IF HR<>HRM OR VR<>VRM THEN GOTO NEWMODE
COLORS(NMODES)=2!^CSNG(PEEK(OS+25))
'
' Get number of bit planes. (Subroutines BGET AND BPUT need it. They
' also need the number of bits per pixel. This is actually what was just
' reported by the VESA bios, above. It will be reobtained from the COLORS
' parameter later.)
'
PLANES(NMODES)=PEEK(OS+24)
'
' Get all modes with required resolution, regardless of color. (Later
' on the one with NC colors, if it exists, will be chosen. (But the
' possibility that the one with the right number of colors will be found
' first is taken into account.))
'
IF COLORS(NMODES)=NC THEN GOTO RETMODE
IF NMODES<256 THEN NMODES=NMODES+1 : GOTO NEWMODE
RETMODE:
'
' Since VESA was detected, store corresponding error code.
'
VESSUP=0
FOR I=1 TO NMODES
K=I
IF COLORS(I)=NC THEN BITSPIXEL=INT(LOG(COLORS(I))/LOG(2)+.001)
IF COLORS(I)=NC THEN MODE=CSNG(MD(I)) : BITPLANES=PLANES(I) : GOTO QUIT
NEXT I
FOR I=1 TO NMODES
K=I
IF COLORS(I)>NC THEN BITSPIXEL=INT(LOG(COLORS(I))/LOG(2)+.001)
IF COLORS(I)>NC THEN MODE=CSNG(MD(I)) : BITPLANES=PLANES(I) : GOTO QUIT
NEXT I
NOSUP:
'
' Requisite VESA mode couldn't be found. Return negative mode value as
' switch for calling routine to recognize that fact.
'
MODE=-1
QUIT:
DEF SEG
END SUB
'
' This is a "functionized" version of code extracted from a more general
' numeric base conversion program by Robert B. Relf, (C) 1984. This just
' uses the part of Mr. Relf's code that converts decimal to binary.
'
FUNCTION BIN$(NUM AS LONG)
DIM X AS INTEGER
NUM=(NUM+65536&) MOD 65536&
BIN1$=""
FOR X=15 TO 0 STEP -1
IF NUM>=(2^X) THEN
BIN1$=BIN1$+"1"
NUM=NUM-(2^X)
ELSE
BIN1$=BIN1$+"0"
END IF
NEXT X
BIN1$=LEFT$(BIN1$,8)+RIGHT$(BIN1$,8)
BIN$=BIN1$
END FUNCTION
'
' This subroutine is the analog of QB's intrinsic PSET statement.
'
SUB BPSET(XCOORD,YCOORD,CL)
'
' Alias inputs in case they were input as numeric literals (which also
' serves to convert the viewport coordinates to screen coordinates).
'
C=CL : X=XCOORD+VXL : Y=YCOORD+VYL
'
' Enforce viewport constraints.
'
IF X<VXL THEN X=VXL
IF Y<VYL THEN Y=VYL
IF X>VXR THEN X=VXR
IF Y>VYR THEN Y=VYR
INREGS.BX=256*CINT(ACPAGE)
IF C<0 THEN C=DEFLTC
INREGS.AX=3072+CINT(C)
INREGS.CX=CINT(X)
INREGS.DX=CINT(Y)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
END SUB
'
' Subroutine BLINE emulates the functionality of QB's LINE statement.
' Except for LINE's "()" and "-" notation, BLINE's syntax is pretty much
' the same as LINE's. The line style option is not supported here and
' the parameter specifying whether the drawn object is a line, box, or
' filled box ("L", "B", or "BF") must be in quotes in the CALL statement.
' Other than that, all parameters must be specified in the CALL.
'
SUB BLINE(XLC,YLC,XRC,YRC,CL,BOX$)
'
' Alias input variables / convert to screen coordinates.
'
B$=UCASE$(BOX$) : C=CL : XL=XLC+VXL : YL=YLC+VYL : XR=XRC+VXL : YR=YRC+VYL
'
' Enforce viewport constraints (if BVCBL <> 1).
'
IF BVCBL=1 THEN GOTO SKIPCON
IF XL<VXL THEN XL=VXL
IF YL<VYL THEN YL=VYL
IF XR>VXR THEN XR=VXR
IF YR>VYR THEN YR=VYR
SKIPCON:
'
' Set color to default color if it was input as negative.
'
IF C<0 THEN C=DEFLTC
'
' If box isn't to be drawn, draw line.
'
IF B$<>"B" AND B$<>"BF" THEN
IF XL<>XR THEN
'
' Draw nonvertical line.
'
NPIX=CINT(SQR((XR-XL)^2+(YR-YL)^2)+.501)
DXX=(XR-XL)/(NPIX-1)
FOR I=1 TO NPIX
X=(I-1)*DXX+XL
Y=(YR-YL)*(X-XL)/(XR-XL)+YL
INREGS.AX=3072+CINT(C)
INREGS.BX=256*CINT(ACPAGE)
INREGS.CX=CINT(X)
INREGS.DX=CINT(Y)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
NEXT I
ELSE
'
' Draw vertical line. (Watch out for upwardly directed lines and lines
' of zero length.)
'
ST=SGN(YR-YL) : IF ST=0 THEN ST=1
FOR Y=YL TO YR STEP ST
INREGS.AX=3072+CINT(C)
INREGS.BX=256*CINT(ACPAGE)
INREGS.CX=CINT(XL)
INREGS.DX=CINT(Y)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
NEXT Y
END IF
'
' Draw box.
'
ELSE
FOR Y=YL TO YR
INREGS.AX=3072+CINT(C)
INREGS.BX=256*CINT(ACPAGE)
INREGS.CX=CINT(XL)
INREGS.DX=CINT(Y)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
NEXT Y
FOR X=XL+1 TO XR
INREGS.AX=3072+CINT(C)
INREGS.BX=256*CINT(ACPAGE)
INREGS.CX=CINT(X)
INREGS.DX=CINT(YR)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
NEXT X
FOR Y=YR-1 TO YL STEP -1
INREGS.AX=3072+CINT(C)
INREGS.BX=256*CINT(ACPAGE)
INREGS.CX=CINT(XR)
INREGS.DX=CINT(Y)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
NEXT Y
FOR X=XR-1 TO XL+1 STEP -1
INREGS.AX=3072+CINT(C)
INREGS.BX=256*CINT(ACPAGE)
INREGS.CX=CINT(X)
INREGS.DX=CINT(YL)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
NEXT X
END IF
'
' Fill box if told to do so.
'
IF B$="BF" THEN
FOR Y=YL+1 TO YR-1
FOR X=XL+1 TO XR-1
INREGS.AX=3072+CINT(C)
INREGS.BX=256*CINT(ACPAGE)
INREGS.CX=CINT(X)
INREGS.DX=CINT(Y)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
NEXT X
NEXT Y
END IF
END SUB
'
' Subroutine BCIRCLE emulates QB's CIRCLE statement. The center is at
' (XCNT,YCNT), the radius is RAD, the color is CL, the starting angle is
' ST (radians), the ending angle is EN radians, and ASP is the aspect.
' (As always, all parameters must be specified.) If EN = ST, a circle/
' ellipse is drawn.
'
SUB BCIRCLE(XCNT,YCNT,RAD,CL,ST,EN,ASP)
'
' Use double precision calculations, set drawing page, and use default
' color if input color is negative.
'
DIM PI AS DOUBLE,A AS DOUBLE,DA AS DOUBLE,X AS DOUBLE,Y AS DOUBLE,XC AS DOUBLE
DIM YC AS DOUBLE,R AS DOUBLE,ASPECT AS DOUBLE,SA AS DOUBLE,EA AS DOUBLE
R=CDBL(RAD) : ASPECT=CDBL(ASP) : YC=CDBL(YCNT) : XC=CDBL(XCNT) : EA=CDBL(EN)
SA=CDBL(ST) : C=CL
IF ASPECT<0 THEN ASPECT=1#
IF C<0 THEN C=DEFLTC
'
' Define PI and test for/define circle condition.
'
PI=4#*ATN(1#)
IF EA=SA THEN EA=SA+2#*PI
NPIX=CINT(ABS(EA-SA)*R+.501)+1
DA=(EA-SA)/CDBL(NPIX-1)
'
' Draw arc/circle.
'
FOR I=1 TO NPIX
A=DA*CDBL(I-1)+SA
X=XC+R*COS(A) : Y=YC-R*SIN(A)
IF ASPECT>1 THEN X=XC+R*COS(A)/ASPECT
IF ASPECT<1 THEN Y=YC-R*ASPECT*SIN(A)
'
' Enforce viewport constraints.
'
X=X+CDBL(VXL) : Y=Y+CDBL(VYL)
IF X<VXL THEN X=VXL
IF Y<VYL THEN Y=VYL
IF X>VXR THEN X=VXR
IF Y>VYR THEN Y=VYR
INREGS.AX=3072+CINT(C)
INREGS.BX=256*CINT(ACPAGE)
INREGS.CX=CINT(X)
INREGS.DX=CINT(Y)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
NEXT I
END SUB
'
' This is the analog of QB's CLS command. BCLS clears the screen by
' putting it in the same video mode that it's already in. CLSMODE = 0
' yields an effect equivalent to QB's CLS 0 and CLSMODE = 1 is like CLS 1.
' (The CLS 1 emulation does not involve the above mentioned mode change
' operation. It uses the somewhat slower method of drawing a filled box
' with color 0.)
'
'
SUB BCLS(CLSMODE)
'
' Look for CLS 0/1 condition. (If no viewport was defined, CLSMODE = 1
' will be treated as CLS 0.)
'
IF CLSMODE<>1 OR VCOL<0 THEN
'
' How video mode is detected and changed depends on whether or not VESA
' bios is present.
'
IF VESSUP=1 THEN GOTO NOVESA
INREGS.AX=&H4F03
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
INREGS.AX=&H4F02
INREGS.BX=OUTREGS.BX
GOTO SETMODE
NOVESA:
INREGS.AX=&HF00
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
INREGS.AX=OUTREGS.AX AND &HFF
SETMODE:
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
'
' Reset viewport defaults. (Turn off viewport in case it was defined.)
'
VCOL=-1 : VXL=0 : VYL=0 : VXR=HMAX : VYR=VMAX
ELSE
CALL BVIEW(VXL,VYL,VXR,VYR,VCOL,VBORD)
END IF
END SUB
'
' This subroutine sets the default color to CL. (In spite of the "B"
' leading the subroutine name, there is no bios call involved here.)
' Unlike BSCREEN, BCOLOR will allow setting the default color to 0.
'
SUB BCOLOR(CL)
DEFLTC=CL
IF DEFLTC<0 THEN DEFLTC=7
END SUB
'
' BLOCATE emulates QB's LOCATE statement. R is the row and C is the
' column. (LOCATE's cursor control options are not supported.)
'
SUB BLOCATE(R,C)
INREGS.AX=&H200
'
' Get page number to print to.
'
INREGS.BX=256*CINT(ACPAGE)
'
' Bios row and column numbers are zero-based.
'
INREGS.DX=256*CINT(R-1)+CINT(C-1)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
END SUB
'
' BPRINT is the bios emulator for QB's PRINT statement. It prints the
' input character string STRNG$ at the current cursor position. It does
' not give a perfect emulation. Semicolons and commas within STRNG$ are
' printed like any other character. A semicolon at the end of STRNG$,
' however, suspends CR/LF printing just as with PRINT. Hence, consecutive
' BPRINT CALLs can be made to achieve the same affect as with PRINT with
' embedded ";" characters. Similarly, a comma at the end of STRNG$
' suppresses CR/LF printing and positions the cursor for the next BPRINT
' operation on the same line but at column (column after last character
' printed + 14) MOD 14, i.e., it attempts to emulate what an embedded
' comma in a PRINT statement would do. STRNG$ can be a maximum of 126
' characters. (It may be noted that QB functions such as STR$ and HEX$
' can be concatenated with other text to create most any string involving
' whatever numeric output you want.)
'
SUB BPRINT(STRNG$)
DIM A(1 TO 32) AS LONG,ROW AS INTEGER,COL AS INTEGER,BYTE AS INTEGER
DIM L AS INTEGER
'
' Make various initializations. (For one, STRNG$ is aliased with S$.)
'
SM=VARSEG(A(1)) : OS=VARPTR(A(1)) : INREGS.BP=CINT(OS) : S$=STRNG$ : L=LEN(S$)
IF L=0 THEN S$=" " : L=1
IF L>126 THEN L=126
'
' S$ will be stored in array A. Point memory pointer there and
' transfer characters.
'
DEF SEG=SM
IF L>1 THEN
FOR I=1 TO L-1
BYTE=ASC(MID$(S$,I,1))
POKE OS,BYTE
OS=OS+1
NEXT I
END IF
'
' Look for ";" or "," at end of S$. Terminate stored string with CR/LF
' if these characters are absent. Adjust number of characters (L) to be
' printed accordingly.
'
BYTE=ASC(MID$(S$,L,1))
IF BYTE<>59 AND BYTE<>44 THEN
POKE OS,BYTE
OS=OS+1
POKE OS,13
OS=OS+1
POKE OS,10
L=L+2
ELSE
L=L-1
END IF
DEF SEG
'
' Get page to print to and current cursor location and then print string
' there with default color.
'
INREGS.AX=&H300
INREGS.BX=256*CINT(ACPAGE)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
INREGS.AX=&H1301
INREGS.BX=CINT(DEFLTC)+256*CINT(ACPAGE)
INREGS.CX=L
INREGS.DX=OUTREGS.DX
INREGS.ES=CINT(SM)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
IF BYTE=44 THEN
INREGS.AX=&H300
INREGS.BX=256*CINT(ACPAGE)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
ROW=(OUTREGS.DX AND &HFF00)/256
COL=OUTREGS.DX AND &HFF
COL=COL+14
COL=14*INT(CSNG(COL+1)/14+.001)-1
INREGS.AX=&H200
INREGS.BX=256*CINT(ACPAGE)
INREGS.DX=256*ROW+COL
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
END IF
END SUB
'
' This function is the analog of QB's POINT function. Unlike the other
' page-oriented routines, it reads data from the page being displayed.
' (QB's "POINT(number)" function is not emulated here. The pixel color
' attribute returned is a 2-byte integer.)
'
DEFINT B
FUNCTION BPOINT%(XCOORD,YCOORD)
'
' Get displayed page.
'
INREGS.AX=&HF00
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
'
' Translate (XCOORD,YCOORD) to screen coordinates and enforce viewport
' constraints.
'
X=XCOORD+VXL : Y=YCOORD+VYL
IF X<VXL THEN X=VXL
IF Y<VYL THEN Y=VYL
IF X>VXR THEN X=VXR
IF Y>VYR THEN Y=VYR
'
' Get color attribute of pixel at (X,Y).
'
INREGS.AX=&HD00
INREGS.BX=OUTREGS.BX
INREGS.CX=CINT(X)
INREGS.DX=CINT(Y)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
BPOINT=OUTREGS.AX AND &HFF
END FUNCTION
DEFSNG B
'
' This is the analog of QB's graphics VIEW statement. Input positive
' numbers for CL and BORDER to fill the viewport with color CL or draw
' a box around it with color BORDER. (Use BORDER <= 0 to avoid drawing a
' a border. Fill color is set to 0 if CL < 0.)
'
SUB BVIEW(XL,YL,XR,YR,CL,BORDER)
VXL=CINT(XL) : VYL=CINT(YL) : VXR=CINT(XR) : VYR=CINT(YR)
'
' Disallow plotting off-screen and make other reasonable enforcements.
'
IF VXL<0 THEN VXL=0
IF VYL<0 THEN VYL=0
IF VXR>HMAX THEN VXR=HMAX
IF VYR>VMAX THEN VYR=VMAX
IF VXL>HMAX THEN VXL=0
IF VYL>VMAX THEN VYL=0
IF VXR<0 THEN VXR=HMAX
IF VYR<0 THEN VYR=VMAX
IF VXR<=VXL THEN VXL=0 : VXR=HMAX
IF VYR<=VYL THEN VYL=0 : VYR=VMAX
'
' Process CL and BORDER arguments. (Save them in global variables for
' BCLS subroutine.)
'
VCOL=CL : IF VCOL<0 THEN VCOL=0
VBORD=BORDER
'
' Clear viewport (fill with VCOL) and then draw border if appropriate.
' (Send BLINE viewport coordinates--it will convert them back to screen
' coordinates.)
'
CALL BLINE(0!,0!,VXR-VXL,VYR-VYL,VCOL,"BF")
IF VBORD>0 THEN
'
' Border is drawn just outside of viewport unless viewport encroaches on
' screen boundary.
'
XVL=VXL-1 : IF XVL<0 THEN XVL=0
YVL=VYL-1 : IF YVL<0 THEN YVL=0
XVR=VXR+1 : IF XVR>HMAX THEN XVR=HMAX
YVR=VYR+1 : IF YVR>VMAX THEN YVR=VMAX
'
' Turn off BLINE's enforcement of viewport limits. (Turn it back on
' when call to BLINE is finished.)
'
BVCBL=1
CALL BLINE(XVL-VXL,YVL-VYL,XVR-VXL,YVR-VYL,VBORD,"B")
BVCBL=0
END IF
END SUB
'
' This subroutine emulates QB's PAINT statement. (The tiling option
' of QB's PAINT statement is not supported.)
'
SUB BPAINT(XP,YP,CL,BORDER)
DIM CPIXEL AS INTEGER,I AS INTEGER,J AS INTEGER
C=CL : IF C<0 THEN C=DEFLTC
'
' Translate (XP,YP) to screen coordinates.
'
X=XP+VXL : Y=YP+VYL
'
' If (X,Y) isn't within viewport, don't do anything.
'
IF X<VXL OR Y<VYL OR X>VXR OR Y>VYR THEN GOTO LEAVE
'
' Set background color. (Painting will only occur if current pixel is
' set to this color, which will be zero unless a filled viewport is
' active.)
'
CBACK=VCOL : IF CBACK<0 THEN CBACK=0
'
' If (X,Y) is on border of area to be painted, no painting occurs.
'
INREGS.AX=&HD00
INREGS.BX=256*CINT(ACPAGE)
INREGS.CX=CINT(X)
INREGS.DX=CINT(Y)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
CPIXEL=OUTREGS.AX AND &HFF
IF CPIXEL<>CBACK THEN GOTO LEAVE
'
' Begin painting. Do points above input (X,Y) first. (All calls to
' BPSET involve viewport coordinates.)
'
IF CINT(Y)>=VYL THEN
FOR J=CINT(Y) TO VYL STEP -1
'
' Do points to right of input (X,Y) first.
'
IF CINT(X)<=VXR THEN
FOR I=CINT(X) TO VXR
'
' Get pixel color at point (I,J).
'
INREGS.AX=&HD00
INREGS.BX=256*CINT(ACPAGE)
INREGS.CX=I
INREGS.DX=J
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
CPIXEL=OUTREGS.AX AND &HFF
'
' Paint interior/exterior pixel with paint color, border pixel with
' border color (for non-negative BORDER input), or move to next part of
' figure.
'
IF CPIXEL=CBACK THEN CALL BPSET(CSNG(I)-VXL,CSNG(J)-VYL,C)
IF CPIXEL<>CBACK THEN
IF BORDER>=0 THEN CALL BPSET(CSNG(I)-VXL,CSNG(J)-VYL,BORDER)
EXIT FOR
END IF
NEXT I
END IF
'
' Do points to left of input (X,Y).
'
IF CINT(X)-1>=VXL THEN
FOR I=CINT(X)-1 TO VXL STEP -1
INREGS.AX=&HD00
INREGS.BX=256*CINT(ACPAGE)
INREGS.CX=I
INREGS.DX=J
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
CPIXEL=OUTREGS.AX AND &HFF
IF CPIXEL=CBACK THEN CALL BPSET(CSNG(I)-VXL,CSNG(J)-VYL,C)
IF CPIXEL<>CBACK THEN
IF BORDER>=0 THEN CALL BPSET(CSNG(I)-VXL,CSNG(J)-VYL,BORDER)
EXIT FOR
END IF
NEXT I
IF I=CINT(X)-1 THEN EXIT FOR
END IF
NEXT J
END IF
'
' Now do points below input (X,Y).
'
IF CINT(Y)+1<=VYR THEN
FOR J=CINT(Y)+1 TO VYR
IF CINT(X)<=VXR THEN
FOR I=CINT(X) TO VXR
INREGS.AX=&HD00
INREGS.BX=256*CINT(ACPAGE)
INREGS.CX=I
INREGS.DX=J
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
CPIXEL=OUTREGS.AX AND &HFF
IF CPIXEL=CBACK THEN CALL BPSET(CSNG(I)-VXL,CSNG(J)-VYL,C)
IF CPIXEL<>CBACK THEN
IF BORDER>=0 THEN CALL BPSET(CSNG(I)-VXL,CSNG(J)-VYL,BORDER)
EXIT FOR
END IF
NEXT I
END IF
IF CINT(X)-1>=VXL THEN
FOR I=CINT(X)-1 TO VXL STEP -1
INREGS.AX=&HD00
INREGS.BX=256*CINT(ACPAGE)
INREGS.CX=I
INREGS.DX=J
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
CPIXEL=OUTREGS.AX AND &HFF
IF CPIXEL=CBACK THEN CALL BPSET(CSNG(I)-VXL,CSNG(J)-VYL,C)
IF CPIXEL<>CBACK THEN
IF BORDER>=0 THEN CALL BPSET(CSNG(I)-VXL,CSNG(J)-VYL,BORDER)
EXIT FOR
END IF
NEXT I
IF I=CINT(X)-1 THEN EXIT FOR
END IF
NEXT J
END IF
LEAVE:
END SUB
'
' This function emulates QB's POS *and* CRSLIN functions. The current
' row (CROW) is returned via the parameter list and BPOS itself represents
' the current column. (This function operates on the active video page,
' like most of the other page-oriented functions.)
'
FUNCTION BPOS(CROW)
INREGS.AX=&H300
INREGS.BX=256*CINT(ACPAGE)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
CROW=CSNG(OUTREGS.DX AND &HFF00)/256+1
BPOS=CSNG(OUTREGS.DX AND &HFF)+1
END FUNCTION
'
' This subroutine emulates QB's PCOPY statement.
'
SUB BPCOPY(SPAGE,DPAGE)
DIM X AS INTEGER,Y AS INTEGER
FOR Y=0 TO CINT(VMAX)
FOR X=0 TO CINT(HMAX)
'
' Get color attribute of pixel at (X,Y) on SPAGE and set the attribute
' at the same location on DPAGE to this value.
'
INREGS.AX=&HD00
INREGS.BX=256*CINT(SPAGE)
INREGS.CX=X
INREGS.DX=Y
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
INREGS.AX=3072+(OUTREGS.AX AND &HFF)
INREGS.BX=256*CINT(DPAGE)
INREGS.CX=X
INREGS.DX=Y
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
NEXT X
NEXT Y
END SUB
'
' This subroutine emulates QB's graphics GET statement. However, it
' only stores the graphics data in a monochrome format. Unlike GET, you
' do not input the actual name of the array to store the graphics data.
' Instead, after the coordinates for the upper lefthand and lower right-
' hand corners, you input the memory segment and offset of the array in
' which the data is to be stored via the variables SM and OS,
' respectively. The array must be dimensioned in the calling routine
' just as it normally would. SM and OS can be obtained in that routine
' via the commands
'
' SM = VARSEG(A(1))
' OS = VARPTR(A(1))
'
' where the name of the array was taken to "A" just for definitiveness
' and it was assumed that the array elements are 1-based. (If they're
' 0-based, change the "1" to a "0" in the above commands.) Do not forget
' to calculate these memory location parameters or MGET will likely crash
' your computer.
'
SUB MGET(XL,YL,XR,YR,SM,OS)
DIM W AS INTEGER,H AS INTEGER
'
' Alias SM because it will need to be changed if picture requires more
' than 65,535 bytes.
'
SM1=SM
'
' Take into account graphics viewport and make sure rectangular screen
' area is defined correctly.
'
XMIN=VXL+XL : XMAX=VXL+XR : YMIN=VYL+YL : YMAX=VYL+YR
IF XMIN>XMAX THEN SWAP XMIN,XMAX
IF YMIN>YMAX THEN SWAP YMIN,YMAX
'
' Get width and height of screen area and poke them into the array at
' memory location SM1:OS
'
W=CINT(XMAX-XMIN)+1 : H=CINT(YMAX-YMIN)+1
WLOW=W AND &HFF : WHIGH=(W AND &HFF00)/256
HLOW=H AND &HFF : HHIGH=(H AND &HFF00)/256
'
' Set pointer to memory segment.
'
DEF SEG=SM
POKE OS,WLOW
POKE OS+1,WHIGH
POKE OS+2,HLOW
POKE OS+3,HHIGH
'
' Read screen pixels one-by-one, line-by-line. (Define new offset
' variable that can be updated as poking occurs.)
'
OFS=OS+4
'
' Get number of whole bytes in each line and excess number of bits that
' must be padded with zeros to make a complete byte. (Take into account
' graphics viewport.)
'
W8=8*INT(CSNG(W)/8+.001)
PEX=W-W8
FOR J=YMIN TO YMAX
'
' Convert 8 bits at a time in line J to bytes and poke each byte into
' array. (All that matters here is whether the attribute of the pixel is
' 0 or some color. Any color but 0 is treated as a bit of one.)
'
IF W8>0 THEN
FOR I=XMIN TO XMIN+W8-1 STEP 8
V=0
FOR K=1 TO 8
INREGS.AX=&HD00
INREGS.BX=256*CINT(ACPAGE)
INREGS.CX=CINT(I+K-1)
INREGS.DX=CINT(J)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
V=V+SGN(OUTREGS.AX AND &HFF)*2^(8-K)
NEXT K
POKE OFS,V
OFS=OFS+1
'
' Watch out for constraint on offset. If it's too large, move memory
' pointer.
'
IF OFS>65535 THEN
SM1=SM1+4096
OFS=0
DEF SEG=SM1
END IF
NEXT I
END IF
IF PEX>0 THEN
V=0
FOR I=1 TO PEX
INREGS.AX=&HD00
INREGS.BX=256*CINT(ACPAGE)
INREGS.CX=CINT(XMIN+I+W8-1)
INREGS.DX=CINT(J)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
V=V+SGN(OUTREGS.AX AND &HFF)*2^(8-I)
NEXT I
POKE OFS,V
OFS=OFS+1
IF OFS>65535 THEN
SM1=SM1+4096
OFS=0
DEF SEG=SM1
END IF
END IF
NEXT J
'
' Graphics data is transferred. Reset memory pointer.
'
DEF SEG
END SUB
'
' This subroutine emulates QB's graphics PUT statement. Like MGET, it
' only displays a monochrome picture, and instead of inputting the name of
' the array storing the picture, it inputs the memory segment and offset
' of that array. (See MGET for how to get those parameters. Also,
' although the data in the array does not necessarily need to have been
' initially generated by MGET, make sure that data does in fact correspond
' to a monochrome image.) Although MPUT will only display a monochrome
' picture, you can specify the (one) color to plot the lit pixels with via
' the parameter CL. (CL will revert to the default value if you specify
' a non-positive value.) ACT$ is a string variable specifying the action
' verb. It has the same interpretation as with PUT, but only in a mono-
' chrome sense.
'
SUB MPUT(XOFF,YOFF,CL,SM,OS,ACT$)
DIM B AS LONG,BT AS INTEGER,CPIXEL AS INTEGER
'
' Alias action verb and color and look for invalid values.
'
AV$=UCASE$(ACT$)
IF AV$<>"PRESET" AND AV$<>"XOR" AND AV$<>"OR" AND AV$<>"AND" THEN AV$="PSET"
C=CL : IF C<=0 THEN C=DEFLTC
'
' Alias SM because it will need to be changed if picture requires more
' than 65,535 bytes.
'
SM1=SM
'
' Direct memory pointer to picture and peek it out of the array, line-by-
' line, byte-by-byte, and treat bits in each byte as lit or unlit pixels.
'
DEF SEG=SM
'
' First get width and height.
'
W=PEEK(OS)+256*PEEK(OS+1) : H=PEEK(OS+2)+256*PEEK(OS+3)
'
' Get number of bytes in each line and define offset to be updated as
' peeking occurs.
'
BYTES=INT((W+7)/8+.001) : OFS=OS+4
FOR J=1 TO H
'
' Initialize horizontal plot coordinate.
'
X=XOFF
FOR I=1 TO BYTES
'
' Get byte I and convert it to binary string.
'
B=CLNG(PEEK(OFS))
BIT$=BIN$(B)
OFS=OFS+1
'
' Watch out for constraint on offset. If it's too large, move memory
' pointer.
'
IF OFS>65535 THEN
SM1=SM1+4096
OFS=0
DEF SEG=SM1
END IF
'
' Plot bits. (First 8 bits of two-byte string BIT$ don't count--they're
' zero anyway.)
'
FOR K=9 TO 16
BT=VAL(MID$(BIT$,K,1))
'
' If action verb isn't PSET, evaluate its effect on current screen pixel.
'
IF AV$<>"PSET" AND AV$<>"PRESET" THEN
INREGS.AX=&HD00
INREGS.BX=256*CINT(ACPAGE)
INREGS.CX=CINT(X+VXL)
INREGS.DX=CINT(VYL+YOFF+J-1)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
CPIXEL=SGN(OUTREGS.AX AND &HFF)
IF AV$="OR" THEN BT=BT OR CPIXEL
IF AV$="AND" THEN BT=BT AND CPIXEL
IF AV$="XOR" THEN BT=BT XOR CPIXEL
END IF
IF AV$="PRESET" THEN BT=1% AND (NOT BT)
'
' Take into account monochrome color to plot with.
'
BT=CINT(C)*BT
'
' Don't plot bits if they're at a horizontal position past W--these bits
' will exist if W isn't an integral multiple of 8.
'
IF X<=XOFF+W-1 THEN
INREGS.AX=3072+BT
INREGS.BX=256*CINT(ACPAGE)
INREGS.CX=CINT(X+VXL)
INREGS.DX=CINT(YOFF+VYL+J-1)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
END IF
X=X+1
NEXT K
NEXT I
NEXT J
DEF SEG
END SUB
'
' Like, MGET, this subroutine also emulates QB's graphics GET statement.
' However, it supports color and is thus perhaps a better emulation. See
' MGET for further information regarding the variables in the parameter
' list.
'
SUB BGET(XL,YL,XR,YR,SM,OS)
DIM W AS INTEGER,H AS INTEGER,B AS LONG,V AS INTEGER,WBITS AS INTEGER
'
' Alias SM because it will need to be changed if picture requires more
' than 65,535 bytes.
'
SM1=SM
'
' Take into account graphics viewport and make sure rectangular screen
' area is defined correctly.
'
XMIN=VXL+XL : XMAX=VXL+XR : YMIN=VYL+YL : YMAX=VYL+YR
IF XMIN>XMAX THEN SWAP XMIN,XMAX
IF YMIN>YMAX THEN SWAP YMIN,YMAX
'
' Get width and height of screen area and poke them into the array at
' memory location SM1:OS.
'
W=CINT(XMAX-XMIN)+1 : H=CINT(YMAX-YMIN)+1
WBITS=W*INT(BITSPIXEL/BITPLANES+.001)
WLOW=WBITS AND &HFF : WHIGH=(WBITS AND &HFF00)/256
HLOW=H AND &HFF : HHIGH=(H AND &HFF00)/256
'
' Set pointer to memory segment.
'
DEF SEG=SM
POKE OS,WLOW
POKE OS+1,WHIGH
POKE OS+2,HLOW
POKE OS+3,HHIGH
'
' Define new offset variable that can be updated as poking occurs.
'
OFS=OS+4
'
' How graphics data is stored depends on number of bit planes per pixel.
' (If number of bit planes per pixel isn't 4, take it to be one.)
'
IF BITPLANES<>4 THEN
'
' Read screen pixels one-by-one, line-by-line, and poke their attributes
' into memory. (If there is only one bit plane per pixel, the video mode
' likely supports 256 colors and each color requires 8 bits.)
'
FOR J=YMIN TO YMAX
FOR I=XMIN TO XMAX
INREGS.AX=&HD00
INREGS.BX=256*CINT(ACPAGE)
INREGS.CX=CINT(I)
INREGS.DX=CINT(J)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
V=OUTREGS.AX AND &HFF
POKE OFS,V
OFS=OFS+1
'
' Watch out for constraint on offset. If it's too large, move memory
' pointer.
'
IF OFS>65535 THEN
SM1=SM1+4096
OFS=0
DEF SEG=SM1
END IF
NEXT I
NEXT J
ELSE
'
' If there is more than one bit plane per pixel, assume it's four. In
' other words, take the number of possible color attributes to be 16.
' Each attribute requires 4 bits of memory. These bits are labeled red,
' green, blue, and intensity, or RGBI. For each line of pixels, combine
' the red bits into bytes and poke those bytes into memory and then repeat
' for the green, blue, and intensity bits. (One plane graphics are a lot
' simpler!)
'
' In reading the attribute byte from the screen, only last 4 bits of each
' byte means anything here. The neglected bits will be zero for a true
' 16-color mode. (If the neglected bits are in fact nonzero, it's likely
' that your VESA bios didn't return correct information when FINDVESA
' queried it, or else you used the SET MODE##= option of QBSVGA to define
' a 16-color mode. In that situation, QBSVGA will arbitrarily assume that
' the number of bit planes per pixel is one. (But, then, this section of
' the program wouldn't be executing.))
'
DIM RED(1 TO W) AS INTEGER,GREEN(1 TO W) AS INTEGER,BLUE(1 TO W) AS INTEGER
DIM INTENSITY(1 TO W) AS INTEGER
'
' If W isn't an even multiple of 8, extra zero bits must be added to the
' RGBI data for each line to make a complete final byte.
'
W8=8*INT(CSNG(W)/8+.001)
PEX=W-W8
FOR J=YMIN TO YMAX
'
' First, just store the RGBI bits for row J.
'
FOR I=XMIN TO XMAX
INREGS.AX=&HD00
INREGS.BX=256*CINT(ACPAGE)
INREGS.CX=CINT(I)
INREGS.DX=CINT(J)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
B=CLNG(OUTREGS.AX AND &HFF)
BIT$=BIN$(B)
RED(I-XMIN+1)=VAL(MID$(BIT$,13,1))
GREEN(I-XMIN+1)=VAL(MID$(BIT$,14,1))
BLUE(I-XMIN+1)=VAL(MID$(BIT$,15,1))
INTENSITY(I-XMIN+1)=VAL(MID$(BIT$,16,1))
NEXT I
'
' Poke RBGI data into memory.
'
IF W8>0 THEN
FOR I=1 TO W8 STEP 8
BYTE=0
FOR K=1 TO 8
BYTE=BYTE+2^(8-K)*RED(I+K-1)
NEXT K
POKE OFS,BYTE
OFS=OFS+1
IF OFS>65535 THEN
SM1=SM1+4096
OFS=0
DEF SEG=SM1
END IF
NEXT I
END IF
IF PEX>0 THEN
BYTE=0
FOR I=1 TO PEX
BYTE=BYTE+2^(8-I)*RED(I+W8)
NEXT I
POKE OFS,BYTE
OFS=OFS+1
IF OFS>65535 THEN
SM1=SM1+4096
OFS=0
DEF SEG=SM1
END IF
END IF
IF W8>0 THEN
FOR I=1 TO W8 STEP 8
BYTE=0
FOR K=1 TO 8
BYTE=BYTE+2^(8-K)*GREEN(I+K-1)
NEXT K
POKE OFS,BYTE
OFS=OFS+1
IF OFS>65535 THEN
SM1=SM1+4096
OFS=0
DEF SEG=SM1
END IF
NEXT I
END IF
IF PEX>0 THEN
BYTE=0
FOR I=1 TO PEX
BYTE=BYTE+2^(8-I)*GREEN(I+W8)
NEXT I
POKE OFS,BYTE
OFS=OFS+1
IF OFS>65535 THEN
SM1=SM1+4096
OFS=0
DEF SEG=SM1
END IF
END IF
IF W8>0 THEN
FOR I=1 TO W8 STEP 8
BYTE=0
FOR K=1 TO 8
BYTE=BYTE+2^(8-K)*BLUE(I+K-1)
NEXT K
POKE OFS,BYTE
OFS=OFS+1
IF OFS>65535 THEN
SM1=SM1+4096
OFS=0
DEF SEG=SM1
END IF
NEXT I
END IF
IF PEX>0 THEN
BYTE=0
FOR I=1 TO PEX
BYTE=BYTE+2^(8-I)*BLUE(I+W8)
NEXT I
POKE OFS,BYTE
OFS=OFS+1
IF OFS>65535 THEN
SM1=SM1+4096
OFS=0
DEF SEG=SM1
END IF
END IF
IF W8>0 THEN
FOR I=1 TO W8 STEP 8
BYTE=0
FOR K=1 TO 8
BYTE=BYTE+2^(8-K)*INTENSITY(I+K-1)
NEXT K
POKE OFS,BYTE
OFS=OFS+1
IF OFS>65535 THEN
SM1=SM1+4096
OFS=0
DEF SEG=SM1
END IF
NEXT I
END IF
IF PEX>0 THEN
BYTE=0
FOR I=1 TO PEX
BYTE=BYTE+2^(8-I)*INTENSITY(I+W8)
NEXT I
POKE OFS,BYTE
OFS=OFS+1
IF OFS>65535 THEN
SM1=SM1+4096
OFS=0
DEF SEG=SM1
END IF
END IF
NEXT J
END IF
'
' Graphics data is transferred. Reset memory pointer.
'
DEF SEG
END SUB
'
' This subroutine emulates QB's graphics PUT statement in a manner that
' supports color. The variables in the call/parameter list are the same
' as with MPUT except that the CL parameter should now be excluded. (The
' attributes in your picture now determine the colors, not some arbitrary
' single value that you specify.)
'
SUB BPUT(XOFF,YOFF,SM,OS,ACT$)
DIM BT AS INTEGER,CPIXEL AS INTEGER,BYTE AS LONG
'
' Alias action verb and look for invalid values.
'
AV$=UCASE$(ACT$)
IF AV$<>"PRESET" AND AV$<>"XOR" AND AV$<>"OR" AND AV$<>"AND" THEN AV$="PSET"
'
' Alias SM because it will need to be changed if picture requires more
' than 65,535 bytes.
'
SM1=SM
'
' Direct memory pointer to picture and peek it out of the array, line-by-
' line, byte-by-byte, and treat bits in each byte as lit or unlit pixels.
'
DEF SEG=SM
'
' First get width and height.
'
W=PEEK(OS)+256*PEEK(OS+1) : H=PEEK(OS+2)+256*PEEK(OS+3)
W=INT(W*BITPLANES/BITSPIXEL+.001)
'
' Define offset to be updated as peeking occurs.
'
OFS=OS+4
'
' Plot data. How graphics data is stored depends on number of bit planes
' per pixel.
'
IF BITPLANES<>4 THEN
FOR J=1 TO H
'
' Initialize horizontal plot coordinate.
'
X=XOFF
FOR I=1 TO W
BT=PEEK(OFS)
'
' If action verb isn't PSET, evaluate its effect on current screen pixel.
'
IF AV$<>"PSET" AND AV$<>"PRESET" THEN
INREGS.AX=&HD00
INREGS.BX=256*CINT(ACPAGE)
INREGS.CX=CINT(X+VXL)
INREGS.DX=CINT(VYL+YOFF+J-1)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
CPIXEL=OUTREGS.AX AND &HFF
IF AV$="OR" THEN BT=BT OR CPIXEL
IF AV$="AND" THEN BT=BT AND CPIXEL
IF AV$="XOR" THEN BT=BT XOR CPIXEL
END IF
IF AV$="PRESET" THEN BT=&HFF AND (NOT BT)
'
' Plot pixel.
'
INREGS.AX=3072+BT
INREGS.BX=256*CINT(ACPAGE)
INREGS.CX=CINT(X+VXL)
INREGS.DX=CINT(YOFF+VYL+J-1)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
X=X+1
OFS=OFS+1
'
' Watch out for constraint on offset. If it's too large, move memory
' pointer.
'
IF OFS>65535 THEN
SM1=SM1+4096
OFS=0
DEF SEG=SM1
END IF
NEXT I
NEXT J
ELSE
DIM RED(1 TO W) AS INTEGER,GREEN(1 TO W) AS INTEGER,BLUE(1 TO W) AS INTEGER
DIM INTENSITY(1 TO W) AS INTEGER
W8=8*INT(W/8+.001)
PEX=W-W8
FOR J=1 TO H
'
' Get RGBI data for row J.
'
IF W8>0 THEN
FOR I=1 TO W8 STEP 8
BYTE=CLNG(PEEK(OFS))
BIT$=BIN$(BYTE)
FOR K=1 TO 8
RED(K+I-1)=VAL(MID$(BIT$,8+K,1))
NEXT K
OFS=OFS+1
IF OFS>65535 THEN
SM1=SM1+4096
OFS=0
DEF SEG=SM1
END IF
NEXT I
END IF
IF PEX>0 THEN
BYTE=CLNG(PEEK(OFS))
BIT$=BIN$(BYTE)
FOR I=1 TO PEX
RED(I+W8)=VAL(MID$(BIT$,8+I,1))
NEXT I
OFS=OFS+1
IF OFS>65535 THEN
SM1=SM1+4096
OFS=0
DEF SEG=SM1
END IF
END IF
IF W8>0 THEN
FOR I=1 TO W8 STEP 8
BYTE=CLNG(PEEK(OFS))
BIT$=BIN$(BYTE)
FOR K=1 TO 8
GREEN(K+I-1)=VAL(MID$(BIT$,8+K,1))
NEXT K
OFS=OFS+1
IF OFS>65535 THEN
SM1=SM1+4096
OFS=0
DEF SEG=SM1
END IF
NEXT I
END IF
IF PEX>0 THEN
BYTE=CLNG(PEEK(OFS))
BIT$=BIN$(BYTE)
FOR I=1 TO PEX
GREEN(I+W8)=VAL(MID$(BIT$,8+I,1))
NEXT I
OFS=OFS+1
IF OFS>65535 THEN
SM1=SM1+4096
OFS=0
DEF SEG=SM1
END IF
END IF
IF W8>0 THEN
FOR I=1 TO W8 STEP 8
BYTE=CLNG(PEEK(OFS))
BIT$=BIN$(BYTE)
FOR K=1 TO 8
BLUE(K+I-1)=VAL(MID$(BIT$,8+K,1))
NEXT K
OFS=OFS+1
IF OFS>65535 THEN
SM1=SM1+4096
OFS=0
DEF SEG=SM1
END IF
NEXT I
END IF
IF PEX>0 THEN
BYTE=CLNG(PEEK(OFS))
BIT$=BIN$(BYTE)
FOR I=1 TO PEX
BLUE(I+W8)=VAL(MID$(BIT$,8+I,1))
NEXT I
OFS=OFS+1
IF OFS>65535 THEN
SM1=SM1+4096
OFS=0
DEF SEG=SM1
END IF
END IF
IF W8>0 THEN
FOR I=1 TO W8 STEP 8
BYTE=CLNG(PEEK(OFS))
BIT$=BIN$(BYTE)
FOR K=1 TO 8
INTENSITY(K+I-1)=VAL(MID$(BIT$,8+K,1))
NEXT K
OFS=OFS+1
IF OFS>65535 THEN
SM1=SM1+4096
OFS=0
DEF SEG=SM1
END IF
NEXT I
END IF
IF PEX>0 THEN
BYTE=CLNG(PEEK(OFS))
BIT$=BIN$(BYTE)
FOR I=1 TO PEX
INTENSITY(I+W8)=VAL(MID$(BIT$,8+I,1))
NEXT I
OFS=OFS+1
IF OFS>65535 THEN
SM1=SM1+4096
OFS=0
DEF SEG=SM1
END IF
END IF
'
' The rest of this is pretty much like the single bit plane case, above.
'
X=XOFF
FOR I=1 TO W
BT=8*RED(I)+4*GREEN(I)+2*BLUE(I)+INTENSITY(I)
IF AV$<>"PSET" AND AV$<>"PRESET" THEN
INREGS.AX=&HD00
INREGS.BX=256*CINT(ACPAGE)
INREGS.CX=CINT(X+VXL)
INREGS.DX=CINT(VYL+YOFF+J-1)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
CPIXEL=OUTREGS.AX AND &HFF
IF AV$="OR" THEN BT=BT OR CPIXEL
IF AV$="AND" THEN BT=BT AND CPIXEL
IF AV$="XOR" THEN BT=BT XOR CPIXEL
END IF
IF AV$="PRESET" THEN BT=15% AND (NOT BT)
INREGS.AX=3072+BT
INREGS.BX=256*CINT(ACPAGE)
INREGS.CX=CINT(X+VXL)
INREGS.DX=CINT(YOFF+VYL+J-1)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
X=X+1
NEXT I
NEXT J
END IF
DEF SEG
END SUB
'
' This function returns -1 if a mouse driver is installed via interrupt
' 33h. (It should return 0 otherwise. Note the variable type of
' QRYMOUSE.) The number of buttons is returned via the global BUTTONS
' variable.
'
DEFINT Q
FUNCTION QRYMOUSE%
DIM DOSVER AS INTEGER
'
' If DOS version isn't > 1, rodents don't work.
'
INREGS.AX=&H3000
CALL INTERRUPTX(&H21,INREGS,OUTREGS)
DOSVER=OUTREGS.AX AND &HFF
QRYMOUSE=0
IF DOSVER>1 THEN
INREGS.AX=0
CALL INTERRUPTX(&H33,INREGS,OUTREGS)
QRYMOUSE=OUTREGS.AX
BUTTONS=CSNG(OUTREGS.BX)
'
' Set default color for mouse cursor and initialize mouse position
' variables.
'
MCOLOR=15 : XMOUSE=-1 : YMOUSE=-1
END IF
END FUNCTION
DEFSNG Q
'
' This subroutine initializes the mouse motion characteristics. You
' don't generally need to worry about this routine. BSCREEN calls it if
' a mouse driver is present.
'
SUB MOUSINIT
CALL GETLIM
CALL SETLIM(0!,0!,HMAX,VMAX)
END SUB
'
' This subroutine calculates the horizontal (MXMAX) and vertical (MYMAX)
' limits on mouse cursor motion and the horizontal (MDX) and vertical
' (MDY) cursor motion discretization in the current video mode. (There
' are, for example, MDX mouse movement pixels for each horizontal screen
' pixel.) These are global quantites. These limits are the ones set by
' the video state. Subroutine SETLIM can be used to enforce smaller
' constraints. (You don't actually need to call GETLIM; subroutine
' MOUSINIT does that.)
'
SUB GETLIM
MXMAX=0
KX=0
FOR I=0 TO 8000
INREGS.AX=4
INREGS.CX=I
INREGS.DX=0
CALL INTERRUPTX(&H33,INREGS,OUTREGS)
INREGS.AX=3
CALL INTERRUPTX(&H33,INREGS,OUTREGS)
IF OUTREGS.CX=I THEN
KX=KX+1
MXMAX=I
END IF
NEXT I
MYMAX=0
KY=0
FOR I=0 TO 5000
INREGS.AX=4
INREGS.CX=0
INREGS.DX=I
CALL INTERRUPTX(&H33,INREGS,OUTREGS)
INREGS.AX=3
CALL INTERRUPTX(&H33,INREGS,OUTREGS)
IF OUTREGS.DX=I THEN
KY=KY+1
MYMAX=I
END IF
NEXT I
IF KX>1 THEN
MDX=MXMAX/(KX-1)
END IF
IF KY>1 THEN
MDY=MYMAX/(KY-1)
END IF
'
' The values of MXMAX and MYMAX, especially the latter, may or may not be
' particularly meaningful in regard to a specific correlation with the
' particular screen resolution. Make them so.
'
MXMAX=MDX*INT(HMAX/MDX+.001) : MYMAX=MDY*INT(VMAX/MDY+.001)
END SUB
'
' This subroutine sets the limits on the screen over which the mouse
' cursor may move. (XMIN,YMIN) is the upper lefthand corner of the
' rectangle in which the cursor moves and (XMAX,YMAX) is the lower right-
' hand corner. GETLIM should be called before SETLIM (so MDX and MDY can
' be computed properly) and SETLIM aliases the new cursor limits with
' global variables for subroutine GETPOS.
'
SUB SETLIM(XMIN,YMIN,XMAX,YMAX)
'
' Enforce consistency with mouse and screen characteristics in current
' video mode.
'
XMIN1=CINT(MDX)*INT(XMIN/MDX+.501) : IF XMIN1<0 THEN XMIN1=0
XMAX1=CINT(MDX)*INT(XMAX/MDX+.001) : IF XMAX1>MXMAX THEN XMAX1=MXMAX
YMIN1=CINT(MDY)*INT(YMIN/MDY+.501) : IF YMIN1<0 THEN YMIN1=0
YMAX1=CINT(MDY)*INT(YMAX/MDY+.001) : IF YMAX1>MYMAX THEN YMAX1=MYMAX
IF XMAX1<=XMIN1 THEN XMIN1=0 : XMAX1=MXMAX
IF YMAX1<=YMIN1 THEN YMIN1=0 : YMAX1=MYMAX
'
' Restrict horizontal movement.
'
INREGS.AX=7
INREGS.CX=CINT(XMIN1*MDX)
INREGS.DX=CINT(XMAX1*MDX)
CALL INTERRUPTX(&H33,INREGS,OUTREGS)
'
' Restrict vertical movement.
'
INREGS.AX=8
INREGS.CX=CINT(YMIN1*MDY)
INREGS.DX=CINT(YMAX1*MDY)
CALL INTERRUPTX(&H33,INREGS,OUTREGS)
'
' Save mouse constraints in global variables.
'
MXMINC=XMIN1 : MXMAXC=XMAX1 : MYMINC=YMIN1 : MYMAXC=YMAX1
END SUB
'
' This subroutine turns a simulated SVGA mouse cursor on and watches its
' movement around the screen. It returns the (X,Y) screen position of the
' cursor when a button is pressed. BUTTON is output as 0 if the left
' button was pressed, 1 if the right button was pressed, and 2 if the
' middle one (Mouse Systems) was pressed. Don't call this subroutine
' until after calling GETLIM (and SETLIM, if you're using SETLIM at all).
' Also, the mouse routines work exclusively in screen coordinates; they
' make their own bios calls, independently of the bios calls made by the
' other QBSVGA routines. (A consequence of this is that this routine
' only supports use of a mouse in a graphic screen mode. Another
' consequence is that, since the graphics viewport is ignored, the
' coordinates output by GETPOS (and BOXDRAG, below) must be converted to
' viewport coordinates before you use them with the other QBSVGA routines.
' This is done by subtracting VXL from X and VYL from Y, assuming a
' graphics viewport is defined at all.)
'
SUB GETPOS(X,Y,BUTTON)
DIM XOLD AS INTEGER,YOLD AS INTEGER,VPAGE AS INTEGER,I AS INTEGER,XM AS INTEGER
DIM YM AS INTEGER,XOUT(1 TO 3),YOUT(1 TO 3),RODBAK(1 TO 34) AS INTEGER
'
' Mouse motion wouldn't be too useful on non-displayed page. Get visible
' page. (Leave it as stored in the high byte of register BX.)
'
INREGS.AX=&HF00
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
VPAGE=OUTREGS.BX
'
' Save portion of screen where simulated rodent cursor is initially going
' to be positioned in global array RODBAK. (First, fix initial position
' of cursor to avoid crash--or put it at last position of cursor.)
'
INREGS.AX=4
INREGS.CX=CINT(MDX)*XMOUSE
IF INREGS.CX<0 THEN INREGS.CX=CINT(MDX)*INT((MXMAXC+MXMINC)/2/MDX+.001)
INREGS.DX=CINT(MDY)*YMOUSE
IF INREGS.DX<0 THEN INREGS.DX=CINT(MDY)*INT((MYMAXC+MYMINC)/2/MDY+.001)
CALL INTERRUPTX(&H33,INREGS,OUTREGS)
'
' Get unequivocal position of cursor now that its position has been set.
'
INREGS.AX=3
CALL INTERRUPTX(&H33,INREGS,OUTREGS)
YOLD=INT(CSNG(OUTREGS.DX)/MDY+.001) : XOLD=INT(CSNG(OUTREGS.CX)/MDX+.001)
'
' Save portion of background beneath cross-hair.
'
FOR I=1 TO 17
INREGS.AX=&HD00
INREGS.BX=VPAGE
INREGS.CX=XOLD+I-9
INREGS.DX=YOLD
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
RODBAK(I)=OUTREGS.AX AND &HFF
INREGS.AX=&HD00
INREGS.BX=VPAGE
INREGS.CX=XOLD
INREGS.DX=YOLD+I-9
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
RODBAK(I+17)=OUTREGS.AX AND &HFF
NEXT I
'
' CMOT is nonzero when rodent moves. Initially, artificially force
' motion detection and initialize BIOS motion detection function. (Cursor
' is only drawn after cursor motion is detected, rather than continuously,
' to avoid undue "flickering.")
'
CMOT=1
INREGS.AX=&HB
CALL INTERRUPTX(&H33,INREGS,OUTREGS)
'
' Start moving cursor around and wait for button to be pressed. (A
' negative value for BUTTON means that nothing has been pressed yet.)
'
GETBUTTON:
BUTTON=-1
INREGS.AX=5
INREGS.BX=0
CALL INTERRUPTX(&H33,INREGS,OUTREGS)
YOUT(1)=INT(CSNG(OUTREGS.DX)/MDY+.001) : XOUT(1)=INT(CSNG(OUTREGS.CX)/MDX+.001)
IF OUTREGS.BX>0 THEN BUTTON=0
IF BUTTONS>1 THEN
INREGS.AX=5
INREGS.BX=1
CALL INTERRUPTX(&H33,INREGS,OUTREGS)
YOUT(2)=INT(CSNG(OUTREGS.DX)/MDY+.001) : XOUT(2)=INT(CSNG(OUTREGS.CX)/MDX+.001)
IF OUTREGS.BX>0 THEN BUTTON=1
END IF
IF BUTTONS>2 THEN
INREGS.AX=5
INREGS.BX=2
CALL INTERRUPTX(&H33,INREGS,OUTREGS)
YOUT(3)=INT(CSNG(OUTREGS.DX)/MDY+.001) : XOUT(3)=INT(CSNG(OUTREGS.CX)/MDX+.001)
IF OUTREGS.BX>0 THEN BUTTON=2
END IF
'
' Was button pressed?
'
IF BUTTON>=0 THEN GOTO EXITROD
'
' Button wasn't pressed. Get screen position of cursor dynamically.
'
INREGS.AX=3
CALL INTERRUPTX(&H33,INREGS,OUTREGS)
YM=INT(CSNG(OUTREGS.DX)/MDY+.001) : XM=INT(CSNG(OUTREGS.CX)/MDX+.001)
'
' Save portion of screen where simulated cursor is to be and draw cursor.
' (First, however, restore original pixel data.)
'
IF CMOT<>0 THEN
FOR I=1 TO 17
INREGS.AX=3072+RODBAK(I)
INREGS.BX=VPAGE
INREGS.CX=XOLD+I-9
INREGS.DX=YOLD
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
INREGS.AX=3072+RODBAK(I+17)
INREGS.BX=VPAGE
INREGS.CX=XOLD
INREGS.DX=YOLD+I-9
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
NEXT I
FOR I=1 TO 17
INREGS.AX=&HD00
INREGS.BX=VPAGE
INREGS.CX=XM+I-9
INREGS.DX=YM
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
RODBAK(I)=OUTREGS.AX AND &HFF
INREGS.AX=&HD00
INREGS.BX=VPAGE
INREGS.CX=XM
INREGS.DX=YM+I-9
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
RODBAK(I+17)=OUTREGS.AX AND &HFF
NEXT I
XOLD=XM : YOLD=YM
'
' Draw cursor.
'
FOR I=-8 TO 8
INREGS.AX=3072+MCOLOR
INREGS.BX=VPAGE
INREGS.CX=XM+I
INREGS.DX=YM
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
INREGS.AX=3072+MCOLOR
INREGS.BX=VPAGE
INREGS.CX=XM
INREGS.DX=YM+I
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
NEXT I
END IF
'
' Look for cursor motion and update CMOT.
'
INREGS.AX=&HB
CALL INTERRUPTX(&H33,INREGS,OUTREGS)
CMOT=ABS(OUTREGS.CX)+ABS(OUTREGS.DX)
GOTO GETBUTTON
EXITROD:
'
' Output whichever pair of (XOUT,YOUT) corresponds to the button pressed.
'
X=XOUT(BUTTON+1) : Y=YOUT(BUTTON+1)
'
' Save last dynamic position in global variables so next call to GETPOS
' can position cursor to where it was last time.
'
XMOUSE=XM : YMOUSE=YM
'
' Turn cursor off.
'
FOR I=1 TO 17
INREGS.AX=3072+RODBAK(I)
INREGS.BX=VPAGE
INREGS.CX=XOLD+I-9
INREGS.DX=YOLD
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
INREGS.AX=3072+RODBAK(I+17)
INREGS.BX=VPAGE
INREGS.CX=XOLD
INREGS.DX=YOLD+I-9
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
NEXT I
END SUB
'
' Like GETPOS, this subroutine allows a mouse cursor to be moved around
' the screen. However, it doesn't simply return the position (XP,YP) of
' the cursor when a button is pressed. Rather, when a button is pressed,
' it watches for the button to be released, returning both the position
' when the button is pressed and the position (XR,YR) when the button was
' released. In between, the cursor may be moved around and a bounding
' rectangle follows its movement. (The cursor is not shown in this second
' movement phase--the moving corner of the rectangle serves the equivalent
' function.) In other words, this subroutine performs a "click and drag
' with bounding box" operation. It uses GETPOS to find the initial press
' position and returns the button pressed/released as BUTTON. (See GETPOS
' for the interpretation of BUTTON.) The rectangle is drawn with the
' MCOLOR attribute set by QRYMOUSE (or by an explicit assignment after
' QRYMOUSE, via BSCREEN, is used).
'
' Like, GETPOS, the outputs XP, YP, XR, and YR are screen coordinates,
' not viewport coordinates. If a graphics viewport is defined, they must
' be converted to viewport coordinates before using them with the other
' QBSVGA routines. (VXL must be subtracted from XP and XR, and VYL must
' be subtracted from YP and YR.)
'
SUB BOXDRAG(XP,YP,XR,YR,BUTTON)
DIM VPAGE AS INTEGER,I AS INTEGER,XM AS INTEGER,YM AS INTEGER,XSTEP AS INTEGER
DIM YSTEP AS INTEGER,BOXBAK(1 TO 2*(HMAX+VMAX)) AS STRING*1,XOLD AS INTEGER
DIM YOLD AS INTEGER,CTEMP AS INTEGER
'
' Get displayed page and leave it as stored in high byte of BX register.
'
INREGS.AX=&HF00
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
VPAGE=OUTREGS.BX
'
' Get button-press position.
'
CALL GETPOS(XP,YP,BUTTON)
'
' Now watch for button-release. (Initialize release counter, CMOT, and
' motion detector.)
'
CMOT=1
INREGS.AX=&HB
CALL INTERRUPTX(&H33,INREGS,OUTREGS)
INREGS.AX=6
INREGS.BX=CINT(BUTTON)
CALL INTERRUPTX(&H33,INREGS,OUTREGS)
'
' PASS becomes nonzero when box has been drawn at least once. (This is
' necessary in order to keep previous box pixels from being treated as box
' background.)
'
PASS=0
GETRELEASE:
'
' RELEASE = 0 if button has not been released.
'
RELEASE=0
INREGS.AX=6
INREGS.BX=CINT(BUTTON)
CALL INTERRUPTX(&H33,INREGS,OUTREGS)
IF OUTREGS.BX>0 THEN RELEASE=1
'
' Get position of cursor dynamically.
'
INREGS.AX=3
CALL INTERRUPTX(&H33,INREGS,OUTREGS)
YM=INT(CSNG(OUTREGS.DX)/MDY+.001) : XM=INT(CSNG(OUTREGS.CX)/MDX+.001)
IF CMOT<>0 THEN
'
' Save background beneath box and draw it one point at a time.
'
XSTEP=1 : IF XM<CINT(XP) THEN XSTEP=-XSTEP
YSTEP=1 : IF YM<CINT(YP) THEN YSTEP=-YSTEP
'
' Index K counts position in BOXBAK array.
'
K=1
FOR I=CINT(YP) TO YM STEP YSTEP
INREGS.AX=&HD00
INREGS.BX=VPAGE
INREGS.CX=CINT(XP)
INREGS.DX=I
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
CTEMP=OUTREGS.AX AND &HFF
IF PASS=0 OR (PASS>0 AND CTEMP<>MCOLOR) THEN BOXBAK(K)=CHR$(CTEMP)
INREGS.AX=3072+MCOLOR
INREGS.BX=VPAGE
INREGS.CX=CINT(XP)
INREGS.DX=I
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
K=K+1
NEXT I
FOR I=CINT(XP)+XSTEP TO XM STEP XSTEP
INREGS.AX=&HD00
INREGS.BX=VPAGE
INREGS.CX=I
INREGS.DX=YM
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
CTEMP=OUTREGS.AX AND &HFF
IF PASS=0 OR (PASS>0 AND CTEMP<>MCOLOR) THEN BOXBAK(K)=CHR$(CTEMP)
INREGS.AX=3072+MCOLOR
INREGS.BX=VPAGE
INREGS.CX=I
INREGS.DX=YM
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
K=K+1
NEXT I
FOR I=YM-YSTEP TO CINT(YP) STEP -YSTEP
INREGS.AX=&HD00
INREGS.BX=VPAGE
INREGS.CX=XM
INREGS.DX=I
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
CTEMP=OUTREGS.AX AND &HFF
IF PASS=0 OR (PASS>0 AND CTEMP<>MCOLOR) THEN BOXBAK(K)=CHR$(CTEMP)
INREGS.AX=3072+MCOLOR
INREGS.BX=VPAGE
INREGS.CX=XM
INREGS.DX=I
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
K=K+1
NEXT I
FOR I=XM-XSTEP TO CINT(XP)+XSTEP STEP -XSTEP
INREGS.AX=&HD00
INREGS.BX=VPAGE
INREGS.CX=I
INREGS.DX=CINT(YP)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
CTEMP=OUTREGS.AX AND &HFF
IF PASS=0 OR (PASS>0 AND CTEMP<>MCOLOR) THEN BOXBAK(K)=CHR$(CTEMP)
INREGS.AX=3072+MCOLOR
INREGS.BX=VPAGE
INREGS.CX=I
INREGS.DX=CINT(YP)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
K=K+1
NEXT I
'
' Save XM and YM for later background restoration and update PASS.
'
XOLD=XM : YOLD=YM : PASS=1
END IF
'
' Look for cursor motion and update CMOT.
'
INREGS.AX=&HB
CALL INTERRUPTX(&H33,INREGS,OUTREGS)
CMOT=ABS(OUTREGS.CX)+ABS(OUTREGS.DX)
'
' If cursor moved, restore box background in preparation for redrawing
' it. Whether or not cursor moved, if button was released, restore box
' background in preparation for exiting routine.
'
IF CMOT<>0 OR RELEASE=1 THEN
K=1
XSTEP=1 : IF XOLD<CINT(XP) THEN XSTEP=-XSTEP
YSTEP=1 : IF YOLD<CINT(YP) THEN YSTEP=-YSTEP
FOR I=CINT(YP) TO YOLD STEP YSTEP
INREGS.AX=3072+ASC(BOXBAK(K))
INREGS.BX=VPAGE
INREGS.CX=CINT(XP)
INREGS.DX=I
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
K=K+1
NEXT I
FOR I=CINT(XP)+XSTEP TO XOLD STEP XSTEP
INREGS.AX=3072+ASC(BOXBAK(K))
INREGS.BX=VPAGE
INREGS.CX=I
INREGS.DX=YOLD
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
K=K+1
NEXT I
FOR I=YOLD-YSTEP TO CINT(YP) STEP -YSTEP
INREGS.AX=3072+ASC(BOXBAK(K))
INREGS.BX=VPAGE
INREGS.CX=XOLD
INREGS.DX=I
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
K=K+1
NEXT I
FOR I=XOLD-XSTEP TO CINT(XP)+XSTEP STEP -XSTEP
INREGS.AX=3072+ASC(BOXBAK(K))
INREGS.BX=VPAGE
INREGS.CX=I
INREGS.DX=CINT(YP)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
K=K+1
NEXT I
END IF
IF RELEASE=0 THEN GOTO GETRELEASE
'
' Output results.
'
XR=CSNG(XM) : YR=CSNG(YM)
END SUB
'
' This subroutine is a lot like MGET. However, rather than transfer
' the pixel data to an array, it prints it to an HP Laserjet/Deskjet
' printer. Similar to MGET, (XL,YL) are the viewport/screen coordinates
' of upper lefthand corner of the rectangular region on the screen to be
' printed and (XR,YR) are the coordinates of the lower righthand corner.
' DPI is the dots/inch that you want to print at. FF should be input as
' 1! (or 1.) if you want to form feed when you're done printing. (Any
' other value means "no form feed.") Since this subroutine uses the
' LPRINT command, the I/O port is assumed to be LPT1.
'
SUB HPRINT(XL,YL,XR,YR,DPI,FF)
DIM VPAGE AS INTEGER
'
' Presumably, you want to print something on the screen you're looking
' at, not on some other page stored somewhere in memory. Get visible
' page and leave it as stored in BH.
'
INREGS.AX=&HF00
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
VPAGE=OUTREGS.BX
'
' Take into account graphics viewport and make sure rectangular screen
' area is defined correctly.
'
XMIN=VXL+XL : XMAX=VXL+XR : YMIN=VYL+YL : YMAX=VYL+YR
IF XMIN>XMAX THEN SWAP XMIN,XMAX
IF YMIN>YMAX THEN SWAP YMIN,YMAX
'
' Get width of screen area.
'
W=INT(XMAX-XMIN)+1
'
' Get number of whole bytes in each line and excess number of bits that
' must be padded with zeros to make a complete byte.
'
W8=8*INT(W/8+.001)
PEX=W-W8
'
' Set up printer.
'
WIDTH "LPT1:",255
LPRINT CHR$(27);"&l0O";
LPRINT CHR$(27);"*t";LTRIM$(RTRIM$(STR$(DPI)));"R";
BYTES=W8/8+SGN(PEX)
FOR J=YMIN TO YMAX
'
' Convert 8 bits at a time in line J to bytes and print each byte.
' (All that matters here is whether the attribute of the pixel is 0 or
' some color. Any color but 0 is treated as a bit of one.)
'
' First, start raster graphics and tell printer how many bytes are coming
' for Jth line of pixels.
'
LPRINT CHR$(27);"*r0A";CHR$(27);"*b";LTRIM$(RTRIM$(STR$(BYTES)));"W";
'
' Watch out for there being less than 8 columns of pixels to print.
'
IF W8>0 THEN
FOR I=XMIN TO XMIN+W8-1 STEP 8
V=0
FOR K=1 TO 8
INREGS.AX=&HD00
INREGS.BX=VPAGE
INREGS.CX=CINT(I+K-1)
INREGS.DX=CINT(J)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
V=V+SGN(OUTREGS.AX AND &HFF)*2^(8-K)
NEXT K
'
' Print byte.
'
LPRINT CHR$(V);
NEXT I
END IF
'
' Print "excess byte" in row J.
'
IF PEX>0 THEN
V=0
FOR I=1 TO PEX
INREGS.AX=&HD00
INREGS.BX=VPAGE
INREGS.CX=CINT(XMIN+I+W8-1)
INREGS.DX=CINT(J)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
V=V+SGN(OUTREGS.AX AND &HFF)*2^(8-I)
NEXT I
LPRINT CHR$(V);
END IF
'
' End graphics transfer for current row of pixels.
'
LPRINT CHR$(27);"*rbC";
NEXT J
'
' Graphics data is transferred. Form feed printer if FF = 1.
'
IF FF=1 THEN LPRINT CHR$(12);
END SUB
'
' This subroutine prints the portion of a graphics screen within the
' rectangle specified by (XL,YL) and (XR,YR) on a 24-pin Epson LQ
' printer. Like HPRINT, FF is input as 1! to form feed when finished.
'
SUB EPRINT(XL,YL,XR,YR,FF)
DIM VPAGE AS INTEGER
'
' Presumably, you want to print something on the screen you're looking
' at, not on some other page stored somewhere in memory. Get visible
' page and leave it as stored in BH.
'
INREGS.AX=&HF00
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
VPAGE=OUTREGS.BX
'
' Take into account graphics viewport and make sure rectangular screen
' area is defined correctly.
'
XMIN=VXL+XL : XMAX=VXL+XR : YMIN=VYL+YL : YMAX=VYL+YR
IF XMIN>XMAX THEN SWAP XMIN,XMAX
IF YMIN>YMAX THEN SWAP YMIN,YMAX
'
' Get width and height of screen area.
'
W=INT(XMAX-XMIN)+1 : H=INT(YMAX-YMIN)+1
'
' Being a typical dot matrix printer, the Epson LQ prints a column of
' dots as the printhead moves horizontally across the page. In this
' particular case, there are 24 dots in that column. Find the number
' of lines in the picture area that is an integral multiple of 24. The
' bits for the excess lines must be padded with zeros to make a complete
' set of 24.
'
H24=24*INT(H/24+.001)
LEX=H-H24
'
' Set up printer.
'
WIDTH "LPT1:",255
'
' N1 and N2 are the low and high bytes of width W.
'
N2=INT(W/256+.001)
N1=W-256*N2
LPRINT CHR$(27);"3";CHR$(24);
'
' Watch out for there being less than 24 lines of pixels to print.
'
IF H24>0 THEN
FOR J=YMIN TO YMIN+H24-1 STEP 24
'
' Get three bytes corresponding to each column of 24 pixels in pixel
' rows J to J + 23. (All that matters here is whether the attribute of
' the pixel is 0 or some color. Any color but 0 is treated as a bit of
' one.)
'
' First, tell printer how many bits are coming for each row of pixels.
'
LPRINT CHR$(27);"*";CHR$(39);CHR$(N1);CHR$(N2);
FOR I=XMIN TO XMAX
V1=0
V2=0
V3=0
FOR K=1 TO 8
INREGS.AX=&HD00
INREGS.BX=VPAGE
INREGS.CX=CINT(I)
INREGS.DX=CINT(J+K-1)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
V1=V1+SGN(OUTREGS.AX AND &HFF)*2^(8-K)
INREGS.AX=&HD00
INREGS.BX=VPAGE
INREGS.CX=CINT(I)
INREGS.DX=CINT(J+K+7)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
V2=V2+SGN(OUTREGS.AX AND &HFF)*2^(8-K)
INREGS.AX=&HD00
INREGS.BX=VPAGE
INREGS.CX=CINT(I)
INREGS.DX=CINT(J+K+15)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
V3=V3+SGN(OUTREGS.AX AND &HFF)*2^(8-K)
NEXT K
'
' Print 3 bytes.
'
LPRINT CHR$(V1);CHR$(V2);CHR$(V3);
NEXT I
'
' Reset starting print position.
'
LPRINT
NEXT J
END IF
'
' Print excess lines of pixels.
'
IF LEX>0 THEN
LPRINT CHR$(27);"*";CHR$(39);CHR$(N1);CHR$(N2);
FOR I=XMIN TO XMAX
V1=0
V2=0
V3=0
FOR J=1 TO 8
IF J<=LEX THEN
INREGS.AX=&HD00
INREGS.BX=VPAGE
INREGS.CX=CINT(I)
INREGS.DX=CINT(YMIN+J+H24-1)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
V1=V1+SGN(OUTREGS.AX AND &HFF)*2^(8-J)
END IF
IF J+8<=LEX THEN
INREGS.AX=&HD00
INREGS.BX=VPAGE
INREGS.CX=CINT(I)
INREGS.DX=CINT(YMIN+J+H24+7)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
V2=V2+SGN(OUTREGS.AX AND &HFF)*2^(8-J)
END IF
IF J+16<=LEX THEN
INREGS.AX=&HD00
INREGS.BX=VPAGE
INREGS.CX=CINT(I)
INREGS.DX=CINT(YMIN+J+H24+15)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
V3=V3+SGN(OUTREGS.AX AND &HFF)*2^(8-J)
END IF
NEXT J
LPRINT CHR$(V1);CHR$(V2);CHR$(V3);
NEXT I
LPRINT
END IF
'
' Graphics data is transferred. Reset printer line spacing.
'
LPRINT CHR$(27);"2";
'
' Form feed printer if FF = 1.
'
IF FF=1 THEN LPRINT CHR$(12);
END SUB
'
' This subroutine prints the portion of a graphics screen within the
' rectangle specified by (XL,YL) and (XR,YR) using "standard" 8-pin
' graphics commands. It should work with 9-pin printers such as Epsons,
' the Panasonic KX-P1092, the Star SG-10 or 15, etc. (It should also
' work with the Epson LQ, if 8-pin graphics are acceptable.) Like HPRINT
' and EPRINT, FF is input as 1! to form feed when finished. The character
' string PTYPE$ should be input as "S" if your printer is set up in its
' standard or native mode and "I" if it's set up to emulate IBM graphics.
'
SUB PRINT8(XL,YL,XR,YR,FF,PTYPE$)
DIM VPAGE AS INTEGER
'
' Presumably, you want to print something on the screen you're looking
' at, not on some other page stored somewhere in memory. Get visible
' page and leave it as stored in BH.
'
INREGS.AX=&HF00
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
VPAGE=OUTREGS.BX
'
' Take into account graphics viewport and make sure rectangular screen
' area is defined correctly.
'
XMIN=VXL+XL : XMAX=VXL+XR : YMIN=VYL+YL : YMAX=VYL+YR
IF XMIN>XMAX THEN SWAP XMIN,XMAX
IF YMIN>YMAX THEN SWAP YMIN,YMAX
'
' Get width and height of screen area.
'
W=INT(XMAX-XMIN)+1 : H=INT(YMAX-YMIN)+1
'
' Data is sent to the printer one column of 8 dots at a time. Find the
' number of lines in the picture area that is an integral multiple of 8.
' The bits for the excess lines must be padded with zeros to make a
' complete set of 8.
'
H8=8*INT(H/8+.001)
LEX=H-H8
'
' Set up printer.
'
WIDTH "LPT1:",255
'
' N1 and N2 are the low and high bytes of width W.
'
N2=INT(W/256+.001)
N1=W-256*N2
LPRINT CHR$(27);"A";CHR$(8);
IF UCASE$(PTYPE$)="I" THEN LPRINT CHR$(27);"2";
'
' Watch out for there being less than 8 lines of pixels to print.
'
IF H8>0 THEN
FOR J=YMIN TO YMIN+H8-1 STEP 8
'
' Get byte corresponding to each column of 8 pixels in pixel rows J to
' J + 7. (All that matters here is whether the attribute of the pixel is
' 0 or some color. Any color but 0 is treated as a bit of one.)
'
' First, tell printer how many bits are coming for each row of pixels.
'
LPRINT CHR$(27);"L";CHR$(N1);CHR$(N2);
FOR I=XMIN TO XMAX
V=0
FOR K=1 TO 8
INREGS.AX=&HD00
INREGS.BX=VPAGE
INREGS.CX=CINT(I)
INREGS.DX=CINT(J+K-1)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
V=V+SGN(OUTREGS.AX AND &HFF)*2^(8-K)
NEXT K
'
' Print byte.
'
LPRINT CHR$(V);
NEXT I
'
' Reset starting print position.
'
LPRINT
NEXT J
END IF
'
' Print excess lines of pixels.
'
IF LEX>0 THEN
LPRINT CHR$(27);"L";CHR$(N1);CHR$(N2);
FOR I=XMIN TO XMAX
V=0
FOR J=1 TO LEX
INREGS.AX=&HD00
INREGS.BX=VPAGE
INREGS.CX=CINT(I)
INREGS.DX=CINT(YMIN+J+H8-1)
CALL INTERRUPTX(&H10,INREGS,OUTREGS)
V=V+SGN(OUTREGS.AX AND &HFF)*2^(8-J)
NEXT J
LPRINT CHR$(V);
NEXT I
LPRINT
END IF
'
' Graphics data is transferred. Reset printer line spacing.
'
IF UCASE$(PTYPE$)="I" THEN LPRINT CHR$(27);"A";CHR$(12);
LPRINT CHR$(27);"2";
'
' Form feed printer if FF = 1.
'
IF FF=1 THEN LPRINT CHR$(12);
END SUB